package cn.sfrog.project.biz.admin.service.impl;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.*;

import cn.sfrog.common.constant.Constants;
import cn.sfrog.common.exception.LiveException;
import cn.sfrog.common.exception.ServiceException;
import cn.sfrog.common.utils.SecurityUtils;
import cn.sfrog.project.biz.admin.domain.BizLiveRoom;
import cn.sfrog.project.biz.admin.domain.vo.BizLiveRoomFormVO;
import cn.sfrog.project.biz.admin.domain.vo.BizLiveRoomQueryVO;
import cn.sfrog.project.biz.admin.domain.vo.BizLiveRoomVO;
import cn.sfrog.project.biz.admin.mapper.BizLiveRoomMapper;
import cn.sfrog.project.biz.admin.service.IBizLiveRoomService;
import cn.sfrog.project.biz.admin.tencent.TencentLiveApiService;
import cn.sfrog.project.biz.admin.websocket.MessageSocketServer;
import cn.sfrog.project.biz.web.vo.room.*;
import cn.sfrog.system.domain.vo.BizStatusChangeVO;
import cn.sfrog.system.domain.vo.app.AppLiveRoomQueryVO;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.gson.JsonObject;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import javax.annotation.Resource;
import java.util.stream.Collectors;


/**
 * 直播房间Service业务层处理
 *
 * @author dev
 * @date 2024-05-23
 */
@Service
public class BizLiveRoomServiceImpl extends ServiceImpl<BizLiveRoomMapper, BizLiveRoom> implements IBizLiveRoomService {
    @Resource
    private BizLiveRoomMapper bizLiveRoomMapper;

    @Autowired
    private TencentLiveApiService liveApiService;

    @Autowired
    private MessageSocketServer messageSocketServer;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 查询直播房间
     *
     * @param id 直播房间主键
     * @return 直播房间
     */
    @Override
    public BizLiveRoomVO selectBizLiveRoomById(Long id) {
        return bizLiveRoomMapper.selectBizLiveRoomById(id);
    }

    /**
     * 查询直播房间列表
     *
     * @param query 直播房间
     * @return 直播房间
     */
    @Override
    public List<BizLiveRoomVO> selectBizLiveRoomList(BizLiveRoomQueryVO query) {
        return bizLiveRoomMapper.selectBizLiveRoomList(query);
    }


    /**
     * 新增直播房间
     *
     * @param form 直播房间
     * @return 结果
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean insertBizLiveRoom(BizLiveRoomFormVO form) {
        BizLiveRoom bizLiveRoom = new BizLiveRoom();
        BeanUtils.copyProperties(form, bizLiveRoom);
        bizLiveRoom.setCreateTime(new Date());
//        bizLiveRoom.setCreateBy(SecurityUtils.getUsername());
        bizLiveRoom.setUpdateTime(new Date());
//        bizLiveRoom.setUpdateBy(SecurityUtils.getUsername());
        return bizLiveRoom.insert();
    }

    /**
     * 修改直播房间
     *
     * @param form 直播房间
     * @return 结果
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean updateBizLiveRoom(BizLiveRoomFormVO form) {
        BizLiveRoom bizLiveRoom = new BizLiveRoom();
        BeanUtils.copyProperties(form, bizLiveRoom);
        bizLiveRoom.setUpdateTime(new Date());
//        bizLiveRoom.setUpdateBy(SecurityUtils.getUsername());
        return bizLiveRoom.updateById();
    }

    /**
     * 批量删除直播房间
     *
     * @param ids 需要删除的直播房间主键
     * @return 结果
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean deleteBizLiveRoomByIds(Long[] ids) {
        return BizLiveRoom.DAO.delete(Wrappers.lambdaQuery(BizLiveRoom.class).in(BizLiveRoom::getId, (Object[]) ids));
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public boolean changeStatus(BizStatusChangeVO vo) {
        return BizLiveRoom.DAO.update(Wrappers.lambdaUpdate(BizLiveRoom.class).in(BizLiveRoom::getId, (Object[]) vo.getIds()).set(BizLiveRoom::getStatus, vo.getStatus()));
    }


    @Override
    public List<AppLiveRoomResultVO> selectBizLiveRoomList4App(AppLiveRoomQueryVO query) {
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        return bizLiveRoomMapper.selectBizLiveRoomList4App(query)
                .stream()
                .map(appLiveRoomResultVO -> {
                    if (bizLiveRoomMapper.selectRoomIdsFromAppointmentByUserId(userId).contains(Long.parseLong(appLiveRoomResultVO.getRoomId()))) {
                        appLiveRoomResultVO.setAppointmentStatus("1"); // 如果房间ID存在，设置status为1
                    } else {
                        appLiveRoomResultVO.setAppointmentStatus("0"); // 如果房间ID存在，设置status为1
                    }
                    return appLiveRoomResultVO; // 返回处理后的appLiveRoomResultVO
                })
                .collect(Collectors.toList());
    }


    /**
     * 开播
     *
     * @param form
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public AppLiveRoomResultVO startLive(AppLiveRoomFormVO form) {
        LocalDateTime txTime = form.getAppointmentTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        BizLiveRoom blr = bizLiveRoomMapper.selectOne(new LambdaQueryWrapper<BizLiveRoom>()
                .eq(BizLiveRoom::getAnchorId, userId));

        BizLiveRoom bizLiveRoom = new BizLiveRoom();
        BeanUtils.copyProperties(form, bizLiveRoom);
        bizLiveRoom.setTxtime(txTime.toEpochSecond(ZoneOffset.of("+8")));
        AppLiveRoomResultVO appLiveRoomResultVO = new AppLiveRoomResultVO();
        if (blr != null) {
            bizLiveRoom.setId(blr.getId());
            bizLiveRoom.setStatus("0");
            bizLiveRoom.updateById();
        } else {
            throw new LiveException("直播系统异常，用户暂未注册直播间");
        }
        BeanUtils.copyProperties(form, appLiveRoomResultVO);
        appLiveRoomResultVO.setRoomId(String.valueOf(userId));

        appLiveRoomResultVO.setLiveAddress(liveApiService.getPushAndPullStreamUrl(String.valueOf(userId), txTime));
        appLiveRoomResultVO.setGroupId(userId.toString());

        //如果是直接开播，那就直接推送消息到已关注该直播的用户客户端上
        if (form.getIsAppointment().equals("0")) {
            /**
             * 开启直播成功 推送消息到订阅的客户端们
             * 首先查询需要推送的客户端列表即user_id list
             */
            List<Long> userIds = bizLiveRoomMapper.selectUserIdsFromAppointmentByRoomId(userId);
            messageSocketServer.sendGroupMessage(userIds, "您关注的直播间房间号：" + userId + "正在直播，请点击前往该直播间！");
        }

        return appLiveRoomResultVO;
    }

    /**
     * 获取房间信息
     *
     * @param roomId
     * @return
     */
    @Override
    public AppLiveRoomResultVO selectBizLiveRoomInfo(Long roomId) {
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        BizLiveRoom bizLiveRoomVO = bizLiveRoomMapper.selectOne(new LambdaQueryWrapper<BizLiveRoom>()
                .eq(BizLiveRoom::getRoomId, roomId));

        if (bizLiveRoomVO == null) {
            throw new ServiceException("房间id错误，未查询到数据");
        }

        AppLiveRoomResultVO appLiveRoomResultVO = new AppLiveRoomResultVO();
        BeanUtils.copyProperties(bizLiveRoomVO, appLiveRoomResultVO);

        LiveAddressVO pullStreamUrl = liveApiService.getPushAndPullStreamUrl(bizLiveRoomVO.getRoomId(),
                LocalDateTime.ofInstant(Instant.ofEpochMilli(bizLiveRoomVO.getTxtime() * 1000), ZoneId.systemDefault()));
        appLiveRoomResultVO.setLiveAddress(pullStreamUrl);
        appLiveRoomResultVO.setGroupId(bizLiveRoomVO.getRoomId());
        appLiveRoomResultVO.setIsAppointment(bizLiveRoomMapper.selectIsAppointmentByUserIdAndRoomId(roomId.toString(), userId) > 0 ? "0" : "1");


        //获取连麦列表
        String setKey = Constants.LIVE_WHEAT_SET_KEY + roomId;
        // 获取 ZSet 中的元素，按分数排序
        Set<Object> zSetRange = redisTemplate.opsForZSet().range(setKey, 0, -1);
        // 创建一个空的列表来存储TrtcStreamResultVO对象
        List<TrtcStreamResultVO> wheatList = new ArrayList<>();

        // 遍历ZSet成员，创建TrtcStreamResultVO对象并添加到列表中
        for (Object member : zSetRange) {
            TrtcStreamResultVO vo = new TrtcStreamResultVO();
            vo.setUserId(member.toString());
            // 假设pull和push的值是从其他数据源获取，或者有默认值
            String[] trtcStreamUrl = liveApiService.getTrtcStreamUrl(member.toString());
            vo.setPushTrtcUrl(trtcStreamUrl[0]);
            vo.setPullTrtcUrl(trtcStreamUrl[1]);
            wheatList.add(vo);
        }


        appLiveRoomResultVO.setWheatList(wheatList);
        return appLiveRoomResultVO;
    }

    /**
     * 关闭我的直播间
     *
     * @return
     */
    @Override
    public Boolean stopLiveRoom() {
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        return BizLiveRoom.DAO.update(Wrappers.lambdaUpdate(BizLiveRoom.class)
                .eq(BizLiveRoom::getRoomId, userId)
                .set(BizLiveRoom::getStatus, 1)
                .set(BizLiveRoom::getIsAppointment, 0));
    }

    /**
     * 这里做预约功能
     */
    @Override
    public Boolean appointment(AppLiveRoomAppointmentVo appLiveRoomAppointmentVo) {
        String roomId = appLiveRoomAppointmentVo.getRoomId();
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        boolean exists = bizLiveRoomMapper.exists(Wrappers.lambdaQuery(BizLiveRoom.class).eq(BizLiveRoom::getRoomId, roomId));
        if (!exists) {
            throw new LiveException("房间号不存在");
        }

        //预约
        if (appLiveRoomAppointmentVo.getAppointmentType() == 1) {
            return bizLiveRoomMapper.appointmentByRoomId(roomId, userId);
        } else {
            //取消预约
            return bizLiveRoomMapper.cancelAppointByRoomId(roomId, userId);
        }

    }

    /**
     * 发送邻近开播提醒
     * 临近5分钟发送提醒
     */
    @Override
    public void sendLivePlayNotifyMessage() {
        //查询是预约直播的直播间列表
//        List<BizLiveRoom> bizLiveRooms = bizLiveRoomMapper.selectList(Wrappers.lambdaQuery(BizLiveRoom.class).eq(BizLiveRoom::getIsAppointment, 1));
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 计算5分钟后的时间
        LocalDateTime fiveMinutesLater = now.plus(5, ChronoUnit.MINUTES);

        // 将LocalDateTime转换为Date
        Date startTime = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
        Date endTime = Date.from(fiveMinutesLater.atZone(ZoneId.systemDefault()).toInstant());

        // 使用Wrappers.lambdaQuery构建查询条件
        List<BizLiveRoom> bizLiveRooms = bizLiveRoomMapper.selectList(
                Wrappers.<BizLiveRoom>lambdaQuery()
                        .eq(BizLiveRoom::getIsAppointment, 1) // IsAppointment 为1
                        .between(BizLiveRoom::getAppointmentTime, startTime, endTime)); //

        for (BizLiveRoom bizLiveRoom : bizLiveRooms) {
            messageSocketServer.sendGroupMessage(bizLiveRoomMapper.selectUserIdsFromAppointmentByRoomId(Long.parseLong(bizLiveRoom.getRoomId())),
                    "您关注的直播间房间号：" + bizLiveRoom.getRoomId() + " 正在直播，请点击前往该直播间！");
        }
    }

//    @Override
//    public TrtcStreamResultVO getTrtcStream() {
//        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
//        LiveAddressVO url = liveApiService.getPushAndPullStreamUrl(String.valueOf(userId), LocalDateTime.now());
//        return new TrtcStreamResultVO(url.getPushTrtcUrl(), url.getPullTrtcUrl());
//    }


    @Override
    public Integer inoutLiveRoom(AppLiveRoomJoinFormVO vo) {
        String roomId = vo.getRoomId();
//        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
        BizLiveRoom bizLiveRoom = bizLiveRoomMapper.selectOne(Wrappers.lambdaQuery(BizLiveRoom.class).eq(BizLiveRoom::getRoomId, roomId));
        if (bizLiveRoom == null) {
            throw new LiveException("房间不存在");
        }

        int playHeat = 0;
        if (vo.getType() == 1) {
            playHeat = bizLiveRoom.getPlayHeat() + 1;
        } else {
            playHeat = bizLiveRoom.getPlayHeat() - 1;
        }

        bizLiveRoom.setPlayHeat(playHeat);
        bizLiveRoom.updateById();
        return playHeat;
    }


    @Override
    public List<TrtcStreamResultVO> applyWheat(AppLiveRoomApplyWheatFormVO applyWheatVO) {
        String roomId = applyWheatVO.getRoomId();
        String setKey = Constants.LIVE_WHEAT_SET_KEY + roomId;
        Long userId = SecurityUtils.getLoginUser().getUser().getUserId();

        //申请连麦
        if (applyWheatVO.getApplyType() == 1) {
            boolean isExists = redisTemplate.opsForZSet().score(setKey, userId) != null;
            if (!isExists) {
                redisTemplate.opsForZSet().add(setKey, userId, System.currentTimeMillis());
            }
        } else {
            //取消连麦
            redisTemplate.opsForZSet().remove(setKey, userId);
        }


        // 获取 ZSet 中的元素，按分数排序
        Set<Object> zSetRange = redisTemplate.opsForZSet().range(setKey, 0, -1);
        // 创建一个空的列表来存储TrtcStreamResultVO对象
        List<TrtcStreamResultVO> list = new ArrayList<>();

        // 遍历ZSet成员，创建TrtcStreamResultVO对象并添加到列表中
        for (Object member : zSetRange) {
            TrtcStreamResultVO vo = new TrtcStreamResultVO();
            vo.setUserId(member.toString());
            // 假设pull和push的值是从其他数据源获取，或者有默认值
            String[] trtcStreamUrl = liveApiService.getTrtcStreamUrl(member.toString());
            vo.setPushTrtcUrl(trtcStreamUrl[0]);
            vo.setPullTrtcUrl(trtcStreamUrl[1]);
            list.add(vo);
        }

        return list;
    }

    @Override
    public List<String> startWheat(AppLiveRoomStartWheatFormVO vo) {
        Long roomId = SecurityUtils.getLoginUser().getUser().getUserId(); //这里userId 就是主播的房间id
        String setKey = Constants.LIVE_WHEAT_SET_KEY + roomId;

        redisTemplate.opsForZSet().remove(setKey, Long.parseLong(vo.getUserId()));
        // 获取 ZSet 中的元素，按分数排序
        Set<Object> zSetRange = redisTemplate.opsForZSet().range(setKey, 0, -1);

        return zSetRange
                .stream()
                .map(o -> o.toString())
                .collect(Collectors.toList());
    }

    @Override
    public AppLiveRoomResultVO getMyLiveRoomInfo() {
        Long roomId = SecurityUtils.getLoginUser().getUser().getUserId(); //这里userId 就是主播的房间id
        BizLiveRoom bizLiveRoomVO = bizLiveRoomMapper.selectOne(new LambdaQueryWrapper<BizLiveRoom>()
                .eq(BizLiveRoom::getRoomId, roomId));
        if (bizLiveRoomVO == null) {
            throw new ServiceException("房间id错误，未查询到数据");
        }

        AppLiveRoomResultVO appLiveRoomResultVO = new AppLiveRoomResultVO();
        BeanUtils.copyProperties(bizLiveRoomVO, appLiveRoomResultVO);

        LiveAddressVO pullStreamUrl = liveApiService.getPushAndPullStreamUrl(bizLiveRoomVO.getRoomId(),
                LocalDateTime.ofInstant(Instant.ofEpochMilli(bizLiveRoomVO.getTxtime() * 1000), ZoneId.systemDefault()));
        appLiveRoomResultVO.setLiveAddress(pullStreamUrl);
        appLiveRoomResultVO.setGroupId(bizLiveRoomVO.getRoomId());
        return appLiveRoomResultVO;
    }

}